package com.allwees.bs.module.pms.rest;

import cn.hutool.core.lang.Assert;
import com.alibaba.fastjson.JSONObject;
import com.allwees.bs.module.core.annotation.PrintLog;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.base.Splitter;
import com.allwees.bs.core.model.constant.CacheName;
import com.allwees.bs.core.model.product.entity.ProductModel;
import com.allwees.bs.core.modelbase.vo.R;
import com.allwees.bs.module.pms.entity.Product;
import com.allwees.bs.module.pms.entity.ProductFlashDays;
import com.allwees.bs.module.pms.req.*;
import com.allwees.bs.module.pms.req.query.ExportGaSkuQueryReq;
import com.allwees.bs.module.pms.service.BaseProductService;
import com.allwees.bs.module.pms.service.PlatformProductService;
import com.allwees.bs.module.pms.service.ProductMarketingDaysService;
import com.allwees.bs.module.pms.vo.AuditRejectReasonTemplateVo;
import com.allwees.bs.module.pms.vo.ExportGaSkuVo;
import com.allwees.core.cache.RedisUtil;
import com.allwees.core.common.constant.EStatus;
import com.allwees.core.common.util.DateUtil;
import com.allwees.core.common.util.excel.ExcelUtil;
import com.allwees.support.marketing.constant.AdjustPriceRuleCode;
import com.allwees.support.marketing.dto.AdjustProductPriceDTO;
import com.allwees.support.marketing.service.AdjustPriceRuleService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 平台端产品API
 *
 * @author yangylsky
 * @since 2019-12-12
 */
@PrintLog
@Slf4j
@RestController
@RequestMapping("/backstage/api/pms/product/platform")
public class PlatformProductApi extends BaseProductApi<PlatformProductService> {

    @Autowired
    private AdjustPriceRuleService adjustPriceRuleService;

    @Resource
    private BaseProductService baseProductService;

    @Resource
    private ProductMarketingDaysService productMarketingDaysService;

    @Override
    @GetMapping("/{uuid}")
    public R retrieve(@PathVariable("uuid") String uuid) {
        return R.error("请使用接口：/backstage/api/pms/product/{uuid}");
    }

    /**
     * 上架审核（批量）
     *
     * @param req
     * @return
     */
    @PostMapping("/audit")
    public R audit(@RequestBody AuditProductReq req) {
        boService.audit(req);
        return R.ok("审核成功");
    }


    /**
     * 上架审核拒绝理由模板列表
     *
     * @param req
     * @param response
     * @return
     */
    @GetMapping("/audit-reject-reason-template")
    public R auditRejectResonTemplate(HttpServletRequest req, HttpServletResponse response) {
        List<AuditRejectReasonTemplateVo> reasonTemplateVos = new ArrayList<>();
        reasonTemplateVos.add(new AuditRejectReasonTemplateVo(1,"商品图片不清晰"));
        reasonTemplateVos.add(new AuditRejectReasonTemplateVo(2,"商品描述不清晰"));
        reasonTemplateVos.add(new AuditRejectReasonTemplateVo(3,"地方政策限制"));

        return R.ok(reasonTemplateVos);
    }

    /**
     * 禁止出售
     *
     * @return
     */
    @PostMapping("/forbid_the_sale")
    public R forbidTheSale(@RequestBody ProductForbidTheSaleReq req) {
        boService.forbidTheSale(req);
        return R.ok("禁售成功");
    }

    /**
     * 禁止出售
     *
     * @return
     */
    @PostMapping("/lift_ban")
    public R liftBan(@RequestBody ProductLiftBanSaleReq req) {
        boService.liftBan(req);
        return R.ok("解禁成功");
    }

    /**
     * 批量导出GaSku
     *
     * @param req
     * @param response
     * @return
     */
    @GetMapping("/export_ga_skus")
    public R exportGaSkus(ExportGaSkuQueryReq req, HttpServletResponse response) {
        List<ExportGaSkuVo> beans = boService.exportGaSkus(req);
        String fileName = "GaSkus_Top" + req.getTopN() + "_" + DateUtil.formatDate(new Date()) + ".xlsx";
        ExcelUtil.writeExcel(response, beans, fileName, "GaSkus_Top" + req.getTopN(), ExportGaSkuVo.class);
        return null;
    }

    @PostMapping("/batch_update_num")
    public R batchUpdateNumLimitReq(@RequestBody UpdateNumLimitReq req) {
        for(String productUuid : req.getUuids()){
            boService.batchUpdateNumLimitReq(productUuid,req.getNum());
        }
        return R.ok("更新成功");
    }
    /**
     * 批量更新Score
     *
     * @return
     */
    @PostMapping("/batch_update_score")
    public R batchUpdateScore(@RequestBody UpdateScoreReq req) {
        List<Product> products = boService.findByUuids(req.getUuids().toArray(new String[0]));
        if (CollectionUtils.isEmpty(products)) {
            return R.ok("批量更新Score并刷新ProductCache成功");
        }
        double score = req.getScore();
        List<Product> updated = products.stream().map(p -> {
            Product update = new Product();
            update.setId(p.getId());
            update.setScore(score);
            return update;
        }).collect(Collectors.toList());
        baseProductService.updateBatchById(updated);
        return R.ok("批量更新Score并刷新ProductCache成功");
    }

    /**
     * 更新ScoreFactor参数
     *
     * @return
     */
    @GetMapping("/update_score_factors")
    public R updateScoreFactors() {
        return R.ok("更新ScoreFactor参数成功");
    }

    /**
     * 获取支持的加价类型列表
     * @return
     */
    @GetMapping("/price_rule_type")
    public R getPriceRuleCode(){
        List<JSONObject> ruleTypes = Arrays.stream(AdjustPriceRuleCode.values())
                .map(code -> {
                    JSONObject json = new JSONObject();
                    json.put(code.getRuleCode(), code.getRuleName());
                    return json;
                }).collect(Collectors.toList());
        return R.ok(ruleTypes);
    }

    /**
     * 获取加价规则列表
     * @return
     */
    @GetMapping("/price_rule")
    public R AllPriceRules(){
        return R.ok(adjustPriceRuleService.list());
    }

    /**
     *  添加加价规则
     *
     * @return
     */
    @PostMapping("/add_price_rule")
    public R savePriceRule(@Validated(AdjustProductPriceDTO.Add.class) @RequestBody AdjustProductPriceDTO dto) {
        adjustPriceRuleService.saveRule(dto);
        return R.ok();
    }

    /**
     *  修改加价规则
     *
     * @return
     */
    @PostMapping("/update_price_rule")
    public R updatePriceRule(@Validated(AdjustProductPriceDTO.Edit.class) @RequestBody AdjustProductPriceDTO dto) {
        adjustPriceRuleService.updateRule(dto);
        return R.ok();
    }

    /**
     *  禁用加价规则
     *
     * @return
     */
    @PostMapping("/disable_price_rule")
    public R disablePriceRule(@Validated(AdjustProductPriceDTO.De.class) @RequestBody AdjustProductPriceDTO dto) {
        adjustPriceRuleService.disableRule(dto.getId());
        return R.ok();
    }

    /**
     *  启用加价规则
     *
     * @return
     */
    @PostMapping("/enable_price_rule")
    public R enablePriceRule(@Validated(AdjustProductPriceDTO.De.class) @RequestBody AdjustProductPriceDTO dto) {
        adjustPriceRuleService.enableRule(dto.getId());
        return R.ok();
    }

    /**
     * 禁止加价
     *
     * @return
     */
    @PostMapping("/forbid_adjust_price")
    public R forbiddenAdjustPrice(@Validated @RequestBody ForbidAdjustPriceReq req) {
        List<String> uuids =
                Splitter
                        .on(',')
                        .omitEmptyStrings()
                        .trimResults()
                        .splitToList(req.getProductUuids());
        if(uuids.size() > 100){
            return R.error("每次最多禁用100个商品~");
        }
        HashSet<String> set = new HashSet<>(uuids);

        int isForbidden = req.getIsForbidden();
        if(isForbidden > 0){
            isForbidden = 1;
        } else {
            isForbidden = 0;
        }

        int setValue = isForbidden;
        List<Product> products = boService
                        .findByUuids(set)
                        .stream()
                        .filter(product -> product.getForbiddenAdjustPrice() != setValue)
                        .collect(Collectors.toList());

        if(!products.isEmpty()){
            List<Product> update = products.stream().map(p -> {
                Product product = new Product();
                product.setId(p.getId());
                product.setForbiddenAdjustPrice(setValue);
                return product;
            }).collect(Collectors.toList());
            baseProductService.updateBatchById(update);

            //设置禁止加价缓存，防止marketing模块回表
            if(setValue == 1){
                products.forEach(p -> {
                    RedisUtil.hset(CacheName.PROD_FORBID_ADJUST_PRICE,p.getUuid(), 1);
                });
            } else {
                products.forEach(p -> {
                    RedisUtil.hdel(CacheName.PROD_FORBID_ADJUST_PRICE,p.getUuid());
                });
            }
        }
        return R.ok();
    }

    /**
     * 批量设置商品marketingType
     * @param req
     * @return
     */
    @PostMapping("/marketing/set")
    public R setMarketingType(@Validated(SetMarketingTypeReq.Add.class) @RequestBody SetMarketingTypeReq req) {
        Integer marketingType = req.getMarketingType();
        List<Integer> marketingDays = null;
        if (marketingType == ProductModel.MARKETING_TYPE_4){
            marketingDays = checkMarketingDays(req.getMarketingDays());
        }
        List<Product> products = boService.findByUuids(req.getProductUuids());
        if (CollectionUtils.isNotEmpty(products)) {
            List<Product> update = products.stream().map(e -> {
                Product p = new Product();
                p.setId(e.getId());
                p.setMarketingType(marketingType | e.getMarketingType());
                return p;
            }).collect(Collectors.toList());
            baseProductService.updateBatchById(update);

            if (marketingType == ProductModel.MARKETING_TYPE_4 && CollectionUtils.isNotEmpty(marketingDays)){
                for (Integer day : marketingDays) {
                    for (Product product : products) {
                        checkAndSave(product.getUuid(),day);
                    }
                }
            }
            super.removeFromCache(products);
        }
        return R.ok();
    }

    private List<Integer> checkMarketingDays(List<Long> marketingDays){
        List<Integer> days = new ArrayList<>();
        if(CollectionUtils.isEmpty(marketingDays)){
            return days;
        }
        long current = System.currentTimeMillis();
        for (Long marketingDay : marketingDays) {
            Assert.isTrue(marketingDay > current,"活动日期应为美国山地时间将来的某一天");
            days.add(Integer.parseInt(DateUtil.formatDate(new Date(marketingDay), "yyyyMMdd")));
        }
        return days;
    }

    /**
     * 设置闪购商品的闪购日期
     * @param req
     * @return
     */
    @PostMapping("/marketing/flash/set")
    public R setFlashDay(@Validated(SetMarketingTypeReq.Edit.class) @RequestBody SetMarketingTypeReq req) {
        List<Integer> marketingDays = checkMarketingDays(req.getMarketingDays());
        for (Integer day : marketingDays) {
            for (String uuid : req.getProductUuids()) {
                checkAndSave(uuid,day);
            }
        }
        return R.ok();
    }

    private void checkAndSave(String productUuid,Integer marketingDay){
        QueryWrapper<ProductFlashDays> wrapper = Wrappers.<ProductFlashDays>query().eq("product_uuid", productUuid).eq("marketing_day", marketingDay);
        ProductFlashDays one = productMarketingDaysService.getOne(wrapper);
        if(one == null){
            productMarketingDaysService.save(new ProductFlashDays(productUuid, marketingDay));
            return;
        }
        if(one.getStatus() == 0){
            return;
        }
        ProductFlashDays pmd = new ProductFlashDays();
        pmd.setId(one.getId());
        pmd.setStatus(EStatus.NORMAL.value());
        productMarketingDaysService.updateById(pmd);
    }

    /**
     * 批量取消商品marketingType
     * @param req
     * @return
     */
    @PostMapping("/marketing/cancel")
    public R cancelMarkeing(@Validated(SetMarketingTypeReq.Add.class) @RequestBody SetMarketingTypeReq req) {
        List<Product> products = boService.findByUuids(new HashSet<>(req.getProductUuids()));
        if (CollectionUtils.isNotEmpty(products)) {
            Integer marketingType = req.getMarketingType();
            List<Product> update = products
                    .stream()
                    .filter(p -> (p.getMarketingType() & marketingType) == marketingType)
                    .map(e -> {
                        Product p = new Product();
                        p.setId(e.getId());
                        p.setMarketingType(e.getMarketingType() ^ marketingType);
                        return p;
                    }).collect(Collectors.toList());
            baseProductService.updateBatchById(update);

            if (marketingType == ProductModel.MARKETING_TYPE_4){
                int marketingDay = Integer.parseInt(DateUtil.formatDate(new Date(), "yyyyMMdd"));
                Wrapper<ProductFlashDays> updateWrapper = Wrappers.<ProductFlashDays>update().set("status",EStatus.USED.value())
                        .in("product_uuid", req.getProductUuids())
                        .ge("marketing_day",marketingDay);
                productMarketingDaysService.update(updateWrapper);
            }
            super.removeFromCache(products);
        }
        return R.ok();
    }
}
